#!/usr/bin/env python
# -*- coding: utf-8 -*-

from threading import Thread
from DrissionPage import ChromiumPage, ChromiumOptions
from BrowserLogger import Recorder
import time
import os
import logging
import csv

# 设置日志
logger = logging.getLogger(__name__)

def open_browser(thread_id):
    """打开浏览器并访问指定网址"""
    print(f"线程 {thread_id} 启动中...")
    
    # 创建配置对象，并设置自动分配端口
    co = ChromiumOptions().auto_port()
    
    # 创建浏览器页面
    page = ChromiumPage(co)
    
    # 访问目标网址
    page.get("http://wspj.gxmu.edu.cn/login.jsp")
    print(f"线程 {thread_id} 已成功打开浏览器")
    
    # 记录日志
    recorder = Recorder()
    recorder.log(f"线程 {thread_id} 已打开浏览器并访问登录页面")
    
    # 保持浏览器打开状态
    while True:
        try:
            time.sleep(1)
        except KeyboardInterrupt:
            break
    
    # 关闭浏览器
    page.close()
    recorder.log(f"线程 {thread_id} 已关闭浏览器")
    print(f"线程 {thread_id} 已关闭浏览器")

def browser_task(thread_id, account, headless=False, force_eval=False):
    """
    浏览器任务函数，处理单个账号的登录和评教
    
    Args:
        thread_id: 线程ID
        account: 账号信息，包含username和password
        headless: 是否使用无头模式
        force_eval: 是否强制执行评教
    """
    logger.info(f"线程 {thread_id} 启动中，账号: {account['username']}")
    recorder = Recorder()
    recorder.log(f"线程 {thread_id} 启动，账号: {account['username']}")
    
    # 添加重试次数
    max_retries = 5
    for retry_count in range(max_retries):
        recorder.log(f"线程 {thread_id} 第 {retry_count+1}/{max_retries} 次尝试")
        
        try:
            # 创建配置对象，并设置自动分配端口
            co = ChromiumOptions().auto_port()
            if headless:
                co.headless = True
            
            # 创建用户数据目录
            user_data_dir = f"user_data_{thread_id}"
            os.makedirs(user_data_dir, exist_ok=True)
            
            # 设置用户数据目录 - 修正方法
            co.set_argument(f'--user-data-dir={user_data_dir}')
            
            # 创建浏览器页面
            page = ChromiumPage(co)
            
            # 访问登录页面
            page.get("http://wspj.gxmu.edu.cn/login.jsp")
            recorder.log(f"线程 {thread_id} 已访问登录页面")
            
            # 执行登录
            try:
                # 导入登录处理器
                from drissionpage.login_handler import LoginHandler
                
                # 创建登录配置
                login_config = {
                    'login_url': 'http://wspj.gxmu.edu.cn/login.jsp',
                    'username': account['username'],
                    'password': account['password'],
                }
                
                # 创建登录处理器
                login_handler = LoginHandler(login_config)
                login_handler.page = page  # 使用已创建的页面
                
                # 执行登录
                recorder.log(f"线程 {thread_id} 开始登录...")
                login_success = login_handler.login(account['username'], account['password'])
                time.sleep(3)
                
                if login_success:
                    recorder.log(f"线程 {thread_id} 登录成功")
                    
                    # 导航到评教页面
                    if login_handler.navigate_to_evaluation_page():
                        recorder.log(f"线程 {thread_id} 已成功导航到评教页面")
                        
                        # 如果需要执行评教
                        if force_eval:
                            # 导入评教处理模块
                            from drissionpage.evaluation_clicker import EvaluationClicker
                            from drissionpage.url_validator import UrlValidator
                            
                            # 检查是否需要评教
                            validator = UrlValidator(page)
                            if validator.validate_url():
                                recorder.log(f"线程 {thread_id} 发现未完成的评教项，开始执行评教")
                                
                                # 点击评教div
                                if validator.click_evaluation_div():
                                    recorder.log(f"线程 {thread_id} 成功点击评教div")
                                
                                # 创建评教点击器
                                clicker = EvaluationClicker(page)
                                
                                # 处理所有待评教的课程
                                evaluations_completed = 0
                                max_evaluations = 100  # 防止无限循环
                                
                                while evaluations_completed < max_evaluations:
                                    # 点击评价按钮
                                    if clicker.click_evaluation_button():
                                        recorder.log(f"线程 {thread_id} 点击了第{evaluations_completed+1}门课程的评价按钮")
                                        
                                        # 填写评教表单
                                        if clicker.fill_evaluation_form():
                                            recorder.log(f"线程 {thread_id} 完成了第{evaluations_completed+1}门课程的评教")
                                            evaluations_completed += 1
                                            
                                            # 返回评教列表
                                            try:
                                                back_button = page.ele('xpath://a[contains(text(), "返回")] | //button[contains(text(), "返回")]')
                                                if back_button:
                                                    back_button.click()
                                                    time.sleep(0.4)
                                                else:
                                                    page.back()
                                                    time.sleep(0.4)
                                            except Exception as e:
                                                recorder.log(f"线程 {thread_id} 返回评教列表时出错: {e}")
                                                break
                                        else:
                                            recorder.log(f"线程 {thread_id} 填写第{evaluations_completed+1}门课程的评教表单失败")
                                            break
                                    else:
                                        recorder.log(f"线程 {thread_id} 未找到更多待评价课程，评教完成")
                                        break
                                
                                recorder.log(f"线程 {thread_id} 共完成了 {evaluations_completed} 门课程的评教")
                            else:
                                recorder.log(f"线程 {thread_id} 所有评教项已完成，无需评教")
                    else:
                        recorder.log(f"线程 {thread_id} 导航到评教页面失败")
                else:
                    recorder.log(f"线程 {thread_id} 登录失败")
                    
            except Exception as e:
                recorder.log(f"线程 {thread_id} 执行过程中出错: {str(e)}")
            
            # 等待一段时间后关闭浏览器
            time.sleep(3)
            page.close()
            recorder.log(f"线程 {thread_id} 已关闭浏览器")
            
        except Exception as e:
            recorder.log(f"线程 {thread_id} 发生异常: {str(e)}")
        
        # 无论成功还是失败，都等待一段时间后进行下一次尝试
        if retry_count < max_retries - 1:  # 如果不是最后一次尝试
            wait_time = 1  # 等待1秒后重试
            recorder.log(f"线程 {thread_id} 将在 {wait_time} 秒后进行第 {retry_count+2} 次尝试")
            time.sleep(wait_time)
    
    logger.info(f"线程 {thread_id} 任务完成，共尝试 {max_retries} 次")

def run_multi_browser(accounts, thread_count=3, headless=False, force_eval=False):
    """
    运行多线程浏览器
    
    Args:
        accounts: 账号列表，每个元素是包含username和password的字典
        thread_count: 线程数量
        headless: 是否使用无头模式
        force_eval: 是否强制执行评教
    """
    # 确保日志配置
    if not logger.handlers:
        logger.setLevel(logging.INFO)
        handler = logging.StreamHandler()
        formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        handler.setFormatter(formatter)
        logger.addHandler(handler)
    
    logger.info(f"启动多线程浏览器，线程数: {thread_count}，账号数: {len(accounts)}")
    
    # 创建线程列表
    threads = []
    
    # 根据账号数量和线程数确定实际需要的线程数
    actual_thread_count = min(thread_count, len(accounts))
    
    # 创建并启动线程
    for i in range(actual_thread_count):
        if i < len(accounts):  # 确保有足够的账号
            thread = Thread(target=browser_task, args=(i+1, accounts[i], headless, force_eval))
            threads.append(thread)
    
    # 启动所有线程
    for thread in threads:
        thread.start()
        time.sleep(1)  # 稍微延迟，避免同时启动造成资源竞争
    
    # 等待所有线程结束
    for thread in threads:
        thread.join()
    
    logger.info("所有浏览器线程已完成")

def main():
    """主函数，从accounts.csv读取账号并启动多线程浏览器"""
    # 读取accounts.csv中的账号信息
    accounts = []
    try:
        with open('accounts.csv', 'r', encoding='utf-8') as f:
            reader = csv.DictReader(f)
            for row in reader:
                accounts.append({
                    'username': row['username'],
                    'password': row['password']
                })
        
        print(f"成功从accounts.csv读取了{len(accounts)}个账号")
        
        # 运行多线程浏览器，线程数量等于账号数量
        run_multi_browser(accounts, thread_count=len(accounts), headless=False, force_eval=True)
        
    except Exception as e:
        print(f"读取accounts.csv或运行多线程浏览器时出错: {e}")
        
    print("所有浏览器任务已完成")

if __name__ == "__main__":
    main() 